package com.task.manager.service.quartz.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.TriggerBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.task.manager.annotation.TaskJob;
import com.task.manager.domain.Actuator;
import com.task.manager.domain.Task;
import com.task.manager.enums.ActuatorType;
import com.task.manager.mapper.ActuatorMapper;
import com.task.manager.mapper.TaskMapper;
import com.task.manager.service.quartz.ScheduleTriggerService;
import com.task.manager.util.ClassUtil;

@Service("scheduleTriggerService")
public class ScheduleTriggerServiceImpl implements ScheduleTriggerService {
	private static final Logger logger = LoggerFactory.getLogger(ScheduleTriggerServiceImpl.class);
	@Autowired
	private Scheduler scheduler;

	@Autowired
	private TaskMapper taskMapper;

	@Autowired
	private ActuatorMapper actuatorMapper;
	
	private final static String packageName = "com.task.manager.job";

	@SuppressWarnings("unchecked")
	@Override
	public void refreshTrigger() {
		try {
			List<Task> tasks = taskMapper.queryAll();
			Map<String, Actuator> actuatorMap = getActuatorMap();
			scheduler.clear();
			if (!CollectionUtils.isEmpty(tasks)) {
				for (Task task : tasks) {
					try {
						if(!task.getStatus()) {
							continue;
						}
						// 创建JobDetail（数据库中job_name存的任务全路径，这里就可以动态的把任务注入到JobDetail中）
						Actuator actuator = actuatorMap.get(task.getActuatorCode());
						if(actuator == null) {
							logger.info("执行器未找到，任务名称："+task.getTaskName()+",任务code："+task.getTaskCode());
							continue;
						}
						JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(actuator.getActuatorClass())).withIdentity(task.getTaskCode(), "all").build();
						// 表达式调度构建器
						CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(task.getTaskCron());
						// 按新的cronExpression表达式构建一个新的trigger
						CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(task.getTaskCode(), "all").withSchedule(scheduleBuilder).build();
						// 把trigger和jobDetail注入到调度器
						scheduler.scheduleJob(jobDetail, trigger);
					} catch (Exception e) {
						logger.error("单个job刷新失败", e);
					}
				}
			}
		} catch (Exception e) {
			logger.error("定时任务每日刷新触发器任务异常，在ScheduleTriggerServiceImpl的方法refreshTrigger中，异常信息：", e);
		}
	}

	private Map<String, Actuator> getActuatorMap() {
		updateActuatorIntoDb();
		List<Actuator> actuators = actuatorMapper.queryAll();
		if (CollectionUtils.isEmpty(actuators)) {
			return new HashMap<>();
		}
		Map<String, Actuator> actuatorMap = new HashMap<>();
		for (Actuator actuator : actuators) {
			actuatorMap.put(actuator.getActuatorCode(), actuator);
		}
		return actuatorMap;
	}
	
	private void updateActuatorIntoDb(){
		List<Class<?>> jobs = ClassUtil.getClasses(packageName);
		for (Class<?> job : jobs) {
			TaskJob taskJob = job.getAnnotation(TaskJob.class);
			Actuator actuator = actuatorMapper.selectActuatorByCode(taskJob.actuatorCode());
			if(actuator == null) {
				actuator = new Actuator();
				actuator.setActuatorMethod(taskJob.actuatorMethod().name());
				actuator.setActuatorProtocol(taskJob.actuatorProtocol().name());
				actuator.setActuatorClass(taskJob.actuatorClass());
				actuator.setActuatorCode(taskJob.actuatorCode());
				actuator.setActuatorName(taskJob.actuatorName());
				actuator.setActuatorType(ActuatorType.TASK_PACKAGE.name());
				actuatorMapper.insert(actuator);
			}else {
				actuatorMapper.updateByPrimaryKey(actuator);
			}
		}
	}
	
	public static void main(String[] args) {
		ScheduleTriggerServiceImpl serviceImpl = new ScheduleTriggerServiceImpl();
		serviceImpl.updateActuatorIntoDb();
	}

}
